<?php

namespace yunj\app\admin\service\member;

use think\facade\Db;
use yunj\app\admin\enum\State;
use yunj\app\admin\enum\TableBuilderEvent;
use yunj\app\admin\service\auth\AuthService;
use yunj\app\admin\service\Service;
use yunj\app\admin\validate\member\MemberRoleValidate;
use yunj\app\admin\validate\member\MemberValidate;
use yunj\core\builder\YunjForm;
use yunj\core\builder\YunjTable;
use yunj\core\enum\RedisKeyPrefixEnum;
use think\model\relation\BelongsToMany;

class MemberService extends Service {

    /**
     * 获取列表构建器
     * @return YunjTable
     */
    public function getListBuilder(): YunjTable {
        $args = [
            'state' => State::getTableBuilderState(),
            'filter' => function (YunjTable $builder, $state) {
                return [
                    'keywords' => [
                        'title' => '关键词',
                        'verify' => 'chsDash',
                        'placeholder' => '姓名/账户',
                        'auth' => 'yunj_member_list_filter_keywords',
                        "grid" => [12, 3, 3],
                    ],
                    'roleIds' => [
                        'title' => '角色',
                        'type' => 'tree',
                        'nodes' => $this->getListBuilderFilterRoleNodes(),
                        'auth' => 'yunj_member_list_filter_role',
                        "grid" => [12, 3, 3],
                    ],
                    'createTimeRange' => [
                        'title' => '添加时间',
                        'type' => 'date',
                        'range' => true,
                        'auth' => 'yunj_member_list_filter_create_time_range',
                        "grid" => [12, 3, 3],
                        "shortcuts" => [
                            [
                                "text" => "上周",
                                "value" => "()=>{return [yunj.getLastWeekStartDateObj(),yunj.getLastWeekEndDateObj()];}",
                            ],
                            [
                                "text" => "本周",
                                "value" => "()=>{return [yunj.getCurrWeekStartDateObj(),new Date()];}",
                            ],
                            [
                                "text" => "上月",
                                "value" => "()=>{return [yunj.getMonthsStartDateObj(-1),yunj.getMonthsEndDateObj(-1)];}",
                            ],
                            [
                                "text" => "本月",
                                "value" => "()=>{return [yunj.getCurrMonthStartDateObj(),new Date()];}",
                            ],
                            [
                                "text" => "最近一周",
                                "value" => "()=>{return [yunj.getDaysDateObj(-7),new Date()];}",
                            ],
                            [
                                "text" => "最近一月",
                                "value" => "()=>{return [yunj.getMonthsTodayDateObj(-1),new Date()];}",
                            ],
                            [
                                "text" => "最近三月",
                                "value" => "()=>{return [yunj.getMonthsTodayDateObj(-3),new Date()];}",
                            ]
                        ],
                    ]
                ];
            },
            'toolbar' => function (YunjTable $builder, $state) {
                $toolbar = [
                    'add' => ['type' => 'openPopup', 'title' => '添加', 'class' => 'layui-icon-add-circle', 'url' => build_url('yunjAdminMemberAdd'), 'auth' => 'yunj_member_add']
                ];
                switch ($state) {
                    case State::NORMAL:
                        $toolbar += [
                            TableBuilderEvent::RECYLE_BIN => ['title' => '移入回收站', 'type' => 'asyncEvent', 'dropdown' => true, 'auth' => 'yunj_member_recyle_bin'],
                        ];
                        break;
                    case State::RECYLE_BIN:
                        $toolbar += [
                            TableBuilderEvent::NORMAL => ['title' => '恢复正常', 'type' => 'asyncEvent', 'dropdown' => true, 'auth' => 'yunj_member_normal'],
                            TableBuilderEvent::DELETED => ['title' => '永久删除', 'type' => 'asyncEvent', 'dropdown' => true, 'auth' => 'yunj_member_deleted'],
                        ];
                        break;
                }
                return $toolbar;
            },
            'defaultToolbar' => [
                'filter',
                'export' => [
                    'auth' => 'yunj_member_export'
                ]
            ],
            'cols' => function (YunjTable $builder, $state) {
                $cols = [
                    'id' => ['type' => 'checkbox'],
                    'name' => ['title' => '姓名'],
                    'username' => ['title' => '账户'],
                    'roles' => ['title' => '角色'],
                    'last_login_ip' => ['title' => '最后一次登录IP', 'align' => 'center'],
                    'last_login_time' => ['title' => '最后一次登录时间', 'align' => 'center', 'templet' => 'datetime'],
                    'create_time' => ['title' => '添加时间', 'align' => 'center', 'templet' => 'datetime', 'hide' => 'mobileHide'],
                    'last_update_time' => ['title' => '最后一次修改时间', 'align' => 'center', 'templet' => 'datetime', 'hide' => 'yes'],
                    'action' => ['title' => '操作', 'templet' => 'action', 'options' => []]
                ];
                $actionOptions = [
                    'edit' => ['type' => 'openPopup', 'title' => '详情', 'class' => 'layui-icon-survey', 'url' => build_url('yunjAdminMemberEdit'), 'auth' => 'yunj_member_edit']
                ];
                switch ($state) {
                    case State::NORMAL:
                        $actionOptions += [
                            TableBuilderEvent::RECYLE_BIN => ['title' => '移入回收站', 'type' => 'asyncEvent', 'dropdown' => true, 'auth' => 'yunj_member_recyle_bin'],
                        ];
                        break;
                    case State::RECYLE_BIN:
                        $actionOptions += [
                            TableBuilderEvent::NORMAL => ['title' => '恢复正常', 'type' => 'asyncEvent', 'dropdown' => true, 'auth' => 'yunj_member_normal'],
                            TableBuilderEvent::DELETED => ['title' => '永久删除', 'type' => 'asyncEvent', 'dropdown' => true, 'auth' => 'yunj_member_deleted']
                        ];
                        break;
                }
                $cols['action']['options'] = $actionOptions;
                $this->setListBuilderColsAuth($cols);
                return $cols;
            },
            'validate' => MemberValidate::class,
            'count' => function (YunjTable $builder, array $filter) {
                $where = self::getListBuilderFilterWhere($filter);
                return self::getAdminMemberModel()->getOwnCount($where);
            },
            'items' => function (YunjTable $builder, int $page, int $pageSize, array $filter, array $sort) {
                $where = self::getListBuilderFilterWhere($filter);
                $order = ['last_login_time' => 'desc'];
                $items = self::getAdminMemberModel()->getOwnRowsToArray($where, ['*'], $order, $page, $pageSize);
                self::listBuilderItemsAppendRoles($items);
                self::listBuilderItemsAppendAction($items, $filter['state']);
                return $items;
            },
            'event' => function (YunjTable $builder, $event, array $ids) {
                $res = TableBuilderEvent::handleEvent(self::getAdminMemberModel(), $event, $ids, function ($eventObj, $ids, array $modelFunParams) {
                    $currTime = time();
                    $eventVal = $eventObj->getValue();
                    if ($eventVal == TableBuilderEvent::DELETED) {
                        //超管不允许修改
                        [$data, $where] = $modelFunParams;
                        $data['username'] = Db::raw("concat(`username`,'_del_{$currTime}')");
                        $where[] = ['pid', '<>', 0];
                        $modelFunParams = [$data, $where];
                    } elseif ($eventVal == TableBuilderEvent::RECYLE_BIN) {
                        [$data, $where] = $modelFunParams;
                        $where[] = ['pid', '<>', 0];
                        $modelFunParams = [$data, $where];
                    }
                    return $modelFunParams;
                });
                return $res ?: error_json("异常事件[{$event}]");
            },
        ];
        return YT('MemberList', $args);
    }

    /**
     * 设置列表构建器cols表头权限
     * @param array $cols
     */
    private function setListBuilderColsAuth(array &$cols): void {
        $auths = ['last_login_ip', 'last_login_time', 'last_update_time'];
        foreach ($cols as $k => $v) {
            if (in_array($k, ['id', 'action'])) continue;
            $cols[$k]['auth'] = 'yunj_member_list_view_' . (in_array($k, $auths) ? $k : 'normal');
        }
    }

    /**
     * 列表构建器items追加roles角色值
     * @param array $items
     */
    private static function listBuilderItemsAppendRoles(array &$items): void {
        if (!$items) return;
        $ids = array_column($items, 'id');
        $allRoleIds = [];
        $idsMapRoleIds = [];
        $relationArr = self::getAdminMemberRoleRelationModel()->getOwnRowsToArray([['member_id', 'in', $ids]]);
        foreach ($relationArr as $relation) {
            ['member_id' => $memberId, 'role_id' => $roleId] = $relation;
            $idsMapRoleIds[$memberId] = $idsMapRoleIds[$memberId] ?? [];
            $idsMapRoleIds[$memberId][] = $roleId;
            $allRoleIds[] = $roleId;
        }
        $roles = [];
        if ($allRoleIds) {
            $roles = self::getAdminMemberRoleModel()->getColumnOptions('name', [['id', 'in', array_unique($allRoleIds)]], [],['sort' => 'aes'], 'id');
        }
        foreach ($items as &$item) {
            $id = $item['id'];
            $roleNames = [];
            $roleIds = $idsMapRoleIds[$id] ?? [];
            foreach ($roleIds as $roleId) {
                if (isset($roles[$roleId])) $roleNames[] = $roles[$roleId];
            }
            $item['roles'] = implode(',', $roleNames);
        }
    }

    /**
     * 列表构建器items追加action操作栏值
     * @param array $items
     */
    private static function listBuilderItemsAppendAction(array &$items, $state): void {
        foreach ($items as &$item) {
            // 初始超管，不允许执行其他操作
            if ($item['pid'] == 0) {
                $item['action'] = ['edit'];
                continue;
            }
        }
    }

    /**
     * 获取列表构建器表单tree的节点
     * @return array
     */
    private function getListBuilderFilterRoleNodes(): array {
        $nodes = [];
        $items = self::getAdminMemberRoleModel()->getOwnRowsToArray([
            ['state', '=', State::NORMAL]
        ], ['*'], ['sort' => 'aes']);
        foreach ($items as $item) {
            $nodes[] = ['id' => $item['id'], 'name' => $item['name'], 'pid' => 0];
        }
        return $nodes;
    }

    /**
     * 获取列表构建器表单条件
     * @param array $filter
     * @return array
     */
    private static function getListBuilderFilterWhere(array $filter): array {
        $state = $filter['state'];
        $ids = $filter['ids'];
        $keywords = $filter['keywords'] ?? '';
        $roleIds = $filter['roleIds'] ?? '';
        $createTimeRange = $filter['createTimeRange'] ?? '';
        $where = [
            ($state ? ['state', '=', $state] : ['state', '<>', State::DELETED]),
        ];
        if ($keywords) $where[] = ['name|username', 'like', '%' . $keywords . '%'];
        if ($roleIds) {
            $roleIdsMapMemberIds = self::getAdminMemberRoleRelationModel()->getColumnOptions('member_id', [['role_id', 'in', $roleIds]]);
            // 如果不存在就给一个查不到数据的条件
            if (!$roleIdsMapMemberIds) {
                $where[] = ['id', '<', 0];
            } else {
                $ids = array_unique(array_merge($ids, $roleIdsMapMemberIds));
            }
        }
        if ($createTimeRange) {
            if ($createTimeStart = $createTimeRange['start'] ?? '') $where[] = ['create_time', '>=', strtotime($createTimeStart . ' 00:00:00')];
            if ($createTimeEnd = $createTimeRange['end'] ?? '') $where[] = ['create_time', '<=', strtotime($createTimeEnd . ' 23:59:59')];
        }
        if ($ids) $where[] = ['id', 'in', $ids];
        return $where;
    }

    /**
     * 获取表单构建器（系统定义的初始超管不能编辑提交）
     * @param bool $isEdit 是否编辑页
     * @return YunjForm
     */
    public function getFormBuilder(bool $isEdit = false): YunjForm {
        $args = [
            'field' => function (YunjForm $builder) use ($isEdit) {
                $field = [
                    // 账户最多支持45字符串，后面的用于记录删除的标记
                    'username' => ['title' => '账户', 'verify' => 'require|alphaDash|max:45', 'desc' => '只能输入字母/数字/下划线_及短横线-'],
                    'password' => ['title' => '密码', 'verify' => 'alphaDash|max:32', 'desc' => '只能输入字母/数字/下划线_及短横线-'],
                    'name' => ['title' => '姓名', 'verify' => 'require|chsDash|max:32', 'desc' => '只能输入汉字、字母、数字和下划线_及破折号-'],
                    'role_ids' => ['title' => '角色', 'type' => 'tree', 'verify' => 'require', 'nodes' => []],
                ];
                $this->setFormBuilderFieldRoleIdsOptions($field);

                if ($isEdit) {
                    // 编辑
                    $field['id'] = ['type' => 'hidden'];
                    $field['password']['desc'] .= "。留空默认不更改";
                    // 权限
                    $this->setFormBuilderFieldAuth($field);
                    // 判断是否有提交权限
                    if (admin_member_auth_check('yunj_member_edit_submit')) {
                        // 有提交权限，判断是否初始超管
                        $memberData = $builder->getLoadValues();
                        if ($memberData && $memberData['pid'] == 0) {
                            // 初始超管不允许修改角色
                            $field['role_ids']['readonly'] = true;
                            return $field;
                        }
                    } else {
                        // 无提交权限，全部只读
                        foreach ($field as &$v) $v['readonly'] = true;
                    }
                } else {
                    // 新增
                    $field['password']['desc'] .= "。留空默认为123456";
                }
                // 设置栅格布局
                foreach ($field as &$v) {
                    $v['grid'] = [12, "6 l3 r3", "4 l4 r4"];
                }
                return $field;
            },
            'validate' => MemberValidate::class,
            'button' => function () use ($isEdit) {
                if ($isEdit) {
                    if (admin_member_auth_check('yunj_member_edit_submit')) $button = ['reset', 'submit'];
                } else {
                    $button = ['clear', 'submit'];
                }
                return $button ?? [];
            },
            'submit' => function (YunjForm $builder, array $data) {
                return $this->formBuilderSubmit($data);
            }
        ];
        if ($isEdit) {
            $args['load'] = function () {
                return $this->formBuilderLoad();
            };
        }
        return YF('MemberForm', $args);
    }

    // 设置表单构建器字段角色选项
    private function setFormBuilderFieldRoleIdsOptions(array &$field): void {
        $roleNodes = [];
        $roles = self::getAdminMemberRoleModel()->getOwnRowsToArray([
            ['state', '=', State::NORMAL],
        ], ['id', 'name', 'alias'], ['sort' => 'aes']);
        foreach ($roles as $role) {
            $name = $role['name'];
            if ($role['alias']) {
                $name = $name ? ($name . "({$role['alias']})") : $role['alias'];
            }
            $roleNodes[] = ['id' => $role['id'], 'name' => $name, 'pid' => 0];
        }
        $field['role_ids']['nodes'] = $roleNodes;
    }

    // 设置表单构建器字段权限
    private function setFormBuilderFieldAuth(array &$field): void {
        $auths = ['username', 'password', 'role_ids'];
        foreach ($field as $k => $v) {
            $field[$k]['auth'] = 'yunj_member_edit_detail_' . (in_array($k, $auths) ? $k : 'normal');
        }
    }

    /**
     * 表单构建器load
     * @return array|string
     */
    private function formBuilderLoad() {
        $id = request()->get('id');
        if (!$id) return '数据异常';
        $data = self::getAdminMemberModel()->getOwnRowToArray([
            ['id', '=', $id],
            ['state', '<>', State::DELETED],
        ], ['*']);
        if (!$data) return '数据异常';
        $data['role_ids'] = self::getAdminMemberRoleRelationModel()->getColumnOptions('role_id', [['member_id', '=', $id]]);
        return $data;
    }

    /**
     * 表单构建器submit
     * @param array $data
     * @return \yunj\core\response\Json
     */
    private function formBuilderSubmit(array $data) {
        $isEdit = isset($data['dbMemberData']['id']);
        try {
            Db::transaction(function () use ($data, $isEdit) {
                $memberModel = self::getAdminMemberModel();
                $memberRoleRelationModel = self::getAdminMemberRoleRelationModel();
                if ($isEdit) {
                    $memberModel->change($data['dbMemberData']);
                    $memberId = $data['dbMemberData']['id'];
                } else {
                    $memberId = $memberModel->addRow($data['dbMemberData']);
                }
                if (!is_null($data['dbMemberRoleIds'])) {
                    // 删除成员角色关系
                    $memberRoleRelationModel->del([['member_id', '=', $memberId]]);
                    // 新增成员角色关系
                    $relationArr = [];
                    foreach ($data['dbMemberRoleIds'] as $roleId) {
                        $relationArr[] = ['member_id' => $memberId, 'role_id' => $roleId];
                    }
                    $memberRoleRelationModel->addRows($relationArr);
                }
            });
            return success_json(["reload" => true]);
        } catch (\Exception $e) {
            log_exception($e);
            return error_json('管理员' . ($isEdit ? '修改' : '新增') . '失败');
        }
    }

    /**
     * 获取个人信息构建器
     * @return YunjForm
     */
    public function getProfileBuilder(): YunjForm {
        $args = [
            'field' => function (YunjForm $builder) {
                $field = [
                    // 账户最多支持45字符串，后面的用于记录删除的标记
                    'username' => ['title' => '账户', 'verify' => 'require|alphaDash|max:45', 'desc' => '只能输入字母/数字/下划线_及短横线-'],
                    'password' => ['title' => '密码', 'verify' => 'chsDash|max:32', 'desc' => '只能输入字母/数字/下划线_及短横线-。留空默认不更改'],
                    'name' => ['title' => '姓名', 'verify' => 'require|chsDash|max:32', 'desc' => '只能输入汉字、字母、数字和下划线_及破折号-'],
                    'roles' => ['title' => '角色', 'readonly' => true],
                    'create_time' => ['title' => '添加时间', 'type' => 'datetime', 'readonly' => true],
                    'last_update_time' => ['title' => '最后一次修改时间', 'type' => 'datetime', 'readonly' => true],
                ];
                // 设置栅格布局
                foreach ($field as &$v) {
                    $v['grid'] = [12, "4 l4 r4", "4 l4 r4"];
                }
                return $field;
            },
            'validate' => MemberValidate::class,
            'button' => function () {
                return ['reset', 'submit'];
            },
            'load' => function () {
                $member = $this->getMember();
                return [
                    'username' => $member->username,
                    'name' => $member->name,
                    'roles' => implode('、', array_column($member->roles->toArray(), 'name')),
                    'create_time' => $member->create_time,
                    'last_update_time' => $member->last_update_time,
                ];
            },
            'submit' => function (YunjForm $builder, array $data) {
                return $this->profileBuilderSubmit($data);
            }
        ];
        return YF('MemberProfile', $args);
    }

    /**
     * 个人信息构建器submit
     * @param array $data
     * @return \yunj\core\response\Json
     */
    private function profileBuilderSubmit(array $data) {
        try {
            self::getAdminMemberModel()->change($data['dbMemberData']);
            return success_json(["reload" => true]);
        } catch (\Exception $e) {
            log_exception($e);
            return error_json('个人信息修改失败');
        }
    }

}